package com.ruoyi.redis.service.impl;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.redis.entity.SeckillVoucher;
import com.ruoyi.redis.entity.VoucherOrder;
import com.ruoyi.redis.mapper.VoucherOrderMapper;
import com.ruoyi.redis.service.ISeckillVoucherService;
import com.ruoyi.redis.service.IVoucherOrderService;
import com.ruoyi.redis.util.RedisIdWorker;
import com.ruoyi.redis.util.SimpleRedisLock;
import com.ruoyi.redis.util.UserHolder;

/**
 * @Description:
 * @ClassName: VoucherOrderServiceImpl
 * @author syc
 * @date: 2022年6月11日 上午9:44:23
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder>
		implements IVoucherOrderService {

	@Resource
	private ISeckillVoucherService seckillVoucherService;
	@Resource
	private RedisIdWorker redisIdWorker;
	@Resource
	StringRedisTemplate stringRedisTemplate;
	@Resource
	RedissonClient redissonClient;

	// (1) 这种写法看起来是没问题,但是一单碰上高并发,无法保证一人一单了
//	@Override
//	@Transactional
//	public String seckillVoucher(Long voucherId) {
//		// 1.查询优惠券
//		SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
//		// 2.判断秒杀是否开始 
//		if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
//			// 尚未开始
//			return "秒杀尚未开始";
//		}
//		// 3.判断秒杀是否已经结束
//		if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
//			// 已经结束
//		   return "秒杀已经结束";
//		}
//		// 4.判断库存是否充足
//		if (voucher.getStock() < 1) {
//			// 库存不足
//			return "库存不足!";
//		}
//		// 5. 一人一单
//		Long userId = UserHolder.getUser().getId();
//		// 5.1 查询订单
//		Long count = query().eq("user_id", userId).eq("vouchar_id", voucherId).count();
//		// 5.2 判断是否存在
//		if(count > 0) {
//		 	// 用户已经购买过了
//			return "用户已经购买过一次!";
//		}
//		// 5.扣减库存
//		boolean success = seckillVoucherService.update().setSql("stock = stock -1")
//		        .eq("voucher_id", voucherId).gt("stock", 0).update();
//		if (!success) {
//			// 扣减失败
//			return "库存不足";
//		}
//		// 6.创建订单
//		VoucherOrder voucherOrder = new VoucherOrder();
//		// 6.1 订单id
//		long orderId = redisIdWorker.nextId("order");
//		voucherOrder.setId(orderId);
//		// 6.2 用户id
//		
//		voucherOrder.setUserId(userId);
//		// 6.3  代金券id
//		voucherOrder.setVoucherId(voucherId);
//		save(voucherOrder);
//		// 7.返回订单
//		return "orderId:" + orderId;
//	}

	/*------------------------------*/
	// (2) 对属性进行加锁,实现一人一单. 这种只适合单个服务
//	@Override
//	public String seckillVoucher(Long voucherId) {
//		// 1.查询优惠券
//		SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
//		// 2.判断秒杀是否开始
//		if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
//			// 尚未开始
//			return "秒杀尚未开始";
//		}
//		// 3.判断秒杀是否已经结束
//		if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
//			// 已经结束
//			return "秒杀已经结束";
//		}
//		// 4.判断库存是否充足
//		if (voucher.getStock() < 1) {
//			// 库存不足
//			return "库存不足!";
//		}
//		// 5. 一人一单
//		Long userId = UserHolder.getUser().getId();
//		// 7.返回订单
//		synchronized (userId.toString().intern()) {
//			// 获取代理对象(事务)
//			IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
//			return proxy.createVoucherOrder(voucherId, userId);
//		}
//	}
//	@Transactional
//	public String createVoucherOrder(Long voucherId, Long userId) {
//		// 5.1 查询订单
//		Long count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
//		// 5.2 判断是否存在
//		if (count > 0) {
//			// 用户已经购买过了
//			return "用户已经购买过一次!";
//		}
//		// 5.扣减库存
//		boolean success = seckillVoucherService.update().setSql("stock = stock -1").eq("voucher_id", voucherId)
//				.gt("stock", 0).update();
//		if (!success) {
//			// 扣减失败
//			return "库存不足";
//		}
//		// 6.创建订单
//		VoucherOrder voucherOrder = new VoucherOrder();
//		// 6.1 订单id
//		long orderId = redisIdWorker.nextId("order");
//		voucherOrder.setId(orderId);
//		// 6.2 用户id
//		voucherOrder.setUserId(userId);
//		// 6.3 代金券id
//		voucherOrder.setVoucherId(voucherId);
//		save(voucherOrder);
//		return orderId + "";
//	} 
	/*-------------------------end--------------------------------*/

	/*-----------------------一个相对完善的锁,但对于锁的重入,重试,不没有实现--------------------------------*/
//	@Override
//	public String seckillVoucher(Long voucherId) {
//		// 1.查询优惠券
//		SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
//		// 2.判断秒杀是否开始
//		if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
//			// 尚未开始
//			return "秒杀尚未开始";
//		}
//		// 3.判断秒杀是否已经结束
//		if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
//			// 已经结束
//			return "秒杀已经结束";
//		}
//		// 4.判断库存是否充足
//		if (voucher.getStock() < 1) {
//			// 库存不足
//			return "库存不足!";
//		}
//		// 5. 一人一单
//		Long userId = UserHolder.getUser().getId();
//
//		// 创建锁对象
//		SimpleRedisLock lock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
//		// 获取锁
//		boolean islock = lock.tryLock(10);
//		if (!islock) {
//			// 获取锁失败,返回错误没重试
//			return "不允许重复下单";
//		}
//		try {
//			// 获取代理对象(事务)
//			IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
//			return proxy.createVoucherOrder(voucherId, userId);
//
//		} finally {
//			lock.unlock();
//		}
//
//	}
//
//	@Transactional
//	public String createVoucherOrder(Long voucherId, Long userId) {
//		// 5.1 查询订单
//		Long count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
//		// 5.2 判断是否存在
//		if (count > 0) {
//			// 用户已经购买过了
//			return "用户已经购买过一次!";
//		}
//		// 5.扣减库存
//		boolean success = seckillVoucherService.update().setSql("stock = stock -1").eq("voucher_id", voucherId)
//				.gt("stock", 0).update();
//		if (!success) {
//			// 扣减失败
//			return "库存不足";
//		}
//		// 6.创建订单
//		VoucherOrder voucherOrder = new VoucherOrder();
//		// 6.1 订单id
//		long orderId = redisIdWorker.nextId("order");
//		voucherOrder.setId(orderId);
//		// 6.2 用户id
//		voucherOrder.setUserId(userId);
//		// 6.3 代金券id
//		voucherOrder.setVoucherId(voucherId);
//		save(voucherOrder);
//		return orderId + "";
//	}
	/*------------------------end----------------------------------*/
	
	/*-----------------使用redisson-------------------------------*/
	@Override
	public String seckillVoucher(Long voucherId) {
		// 1.查询优惠券
		SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
		// 2.判断秒杀是否开始
		if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
			// 尚未开始
			return "秒杀尚未开始";
		}
		// 3.判断秒杀是否已经结束
		if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
			// 已经结束
			return "秒杀已经结束";
		}
		// 4.判断库存是否充足
		if (voucher.getStock() < 1) {
			// 库存不足
			return "库存不足!";
		}
		// 5. 一人一单
		Long userId = UserHolder.getUser().getId();

		// 创建锁对象
		//SimpleRedisLock lock = new SimpleRedisLock("order:" + userId, stringRedisTemplate);
		RLock lock = redissonClient.getLock("lock:order:" + userId);
		
		
		// 获取锁
		boolean islock;
		try {
			islock = lock.tryLock(1L, TimeUnit.SECONDS);
			//islock = lock.tryLock();
			if (!islock) {
				// 获取锁失败,返回错误没重试
				return "不允许重复下单";
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
		try {
			// 获取代理对象(事务)
			IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
			return proxy.createVoucherOrder(voucherId, userId);

		} finally {
			lock.unlock();
		}

	}

	@Transactional
	public String createVoucherOrder(Long voucherId, Long userId) {
		// 5.1 查询订单
		Long count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
		// 5.2 判断是否存在
		if (count > 0) {
			// 用户已经购买过了
			return "用户已经购买过一次!";
		}
		// 5.扣减库存
		boolean success = seckillVoucherService.update().setSql("stock = stock -1").eq("voucher_id", voucherId)
				.gt("stock", 0).update();
		if (!success) {
			// 扣减失败
			return "库存不足";
		}
		// 6.创建订单
		VoucherOrder voucherOrder = new VoucherOrder();
		// 6.1 订单id
		long orderId = redisIdWorker.nextId("order");
		voucherOrder.setId(orderId);
		// 6.2 用户id
		voucherOrder.setUserId(userId);
		// 6.3 代金券id
		voucherOrder.setVoucherId(voucherId);
		save(voucherOrder);
		return orderId + "";
	}
	
	
	
}
